package agent.behaviour;

import jade.core.AID;
import jade.core.behaviours.TickerBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import util.Constant;
import agent.communication.AgentsCommunicationMsg;
import agent.enums.Ressource;
import agent.enums.TypeAgent;
import agent.model.AbstractAgent;

/**
 * TickerBehaviour qui représente la vie d'un agent.
 * @author Jean-François Augé & Guillaume Poças
 */
public class LiveBehaviour extends TickerBehaviour {

	private static final long serialVersionUID = 1L;

	private AbstractAgent agent;
	private int compteurCyclesMort;
	private int compteurCyclesReproduction;

	/**
	 * Constructeur.
	 * @param a, l'agent au quel a été lié le Behaviour
	 * @param delay, le temps entre chaque déclanchement de la méthode onTick
	 */
	public LiveBehaviour(AbstractAgent a, long delay) {
		super(a, delay);
		agent = a;
		compteurCyclesMort = 0;
		compteurCyclesReproduction = 0;
		setFixedPeriod(true);
	}

	/**
	 * Un cycle dans la vie d'un agent.
	 */
	@Override
	protected void onTick() {
		// variables pour l'annuaire
		DFAgentDescription template = new DFAgentDescription();
		ServiceDescription sd = new ServiceDescription();
		DFAgentDescription[] result = null;
		AID[] agents = null;

		// variables pour l'envoi de messages
		String cmd = "";

		int i = 0;
		double argent = 0, impotsAPayer = 0, argentRestant = 0;

		// test la fin de l'agent
		if(agent.getCycle() > Constant.defaultCycleMax)
			//test si l'agent est le Roi
			if(agent.getAgent().equals(TypeAgent.Roi)){
				System.out.println("Le Roi est mort, vive le Roi !");
				agent.successor();
				agent.closeAgent();
			} else
				//on teste si l'agent s'est reproduit ou pas
				agent.closeAgent();

		// LIVE
		//test de la phase d'impots
		if(((agent.getCycle()*agent.getFrequenceImpots()) == 1) &&
				!agent.getAgent().equals(TypeAgent.Roi) &&
				(agent.getArgent() > 2)) {
			//System.out.println("IMPOOOOOOTS");
			agent.setPhaseImpots(true);

			//recherche du Roi
			sd.setType(Ressource.Prosperite.toString());
			template.addServices(sd);
			try {
				result = DFService.search(myAgent, template);
				agents = new AID[result.length];
				for(i=0; i<result.length; i++)
					agents[i] = result[i].getName();
			} catch (FIPAException fe) {
				fe.printStackTrace();
			}

			if(agents.length>0) {
				argent = agent.getArgent();
				impotsAPayer = (argent*agent.getTauxImpots())/100;
				argentRestant = argent - impotsAPayer;
				System.out.println(agent.getLocalName()+" paie ses impots : "+argent+"-"+impotsAPayer+"= reste "+argentRestant);
				cmd = AgentsCommunicationMsg.INFORM.makeCommand("IMPOTS", String.valueOf(impotsAPayer));
				agent.sendMsg(agents, ACLMessage.INFORM, cmd);
				//agent.acheteRessource(impotsAPayer, 0.0);
				agent.setArgent(argentRestant);
			}

			agent.setPhaseImpots(false);
		}

		//mise à jour de la satisfaction:
		//satisfaction = 1 si stock de consommation non nul
		if(agent.getStockConsommationCourant() > 0){
			agent.setSatisfaction(1.0);
			//System.out.println(agent.getLocalName()+" stock:"+agent.getStockProductionCourant());

			//si a de l'argent, augmente les prix
			if(agent.getArgent() >= Constant.seuilRichesse)	agent.prixAugmente();
		}
		//agent non satisfait car plus de stock de consommation
		else{
			agent.decreaseSatisfaction();
			//satisfaction remonte si stock de production plein = arret du travail
			if(agent.getStockProductionCourant() == agent.getStockProduitMax()){
				agent.increaseHalfSatisfaction();
				agent.setProductionEnCours(false);
			}
			else	agent.setProductionEnCours(true);

			//si plus d'argent, baisse de prix
			if(agent.getArgent() <= Constant.seuilPauvrete)	agent.prixBaisse();
		}
		
		agent.setSatisfactionTotal(agent.getSatisfactionTotal()+agent.getSatisfaction());

		//tests mort/reproduction en fonction de la satisfaction
		if(agent.getSatisfaction() >= agent.getSatisfactionHaut()) {
			compteurCyclesReproduction++;
			compteurCyclesMort = 0;
			if(compteurCyclesReproduction >= Constant.defaultSeuilCycleReproduction)
				//TODO reproduction => OK ?!
				if(!agent.getAgent().equals(TypeAgent.Roi)) {
					//try {
					// TODO nombre cycle non constant
					//agent.getRoyaume().creeAgent(agent.getAgent(), 1, agent.getCycle(), agent.getCycleMax()-agent.getCycle());
					agent.cloneAgent();
					//if(Constant.DEBUG)	System.out.println("Reproduction!!");
					compteurCyclesReproduction = 0;
					/*} catch (StaleProxyException e) {
						e.printStackTrace();
					}*/
				}
		}
		else if(agent.getSatisfaction() <= agent.getSatisfactionBas()) {
			compteurCyclesReproduction = 0;
			compteurCyclesMort++;
			if(compteurCyclesMort >= Constant.defaultSeuilCycleCriticite)
				//agent.getRoyaume().decreaseNombreAgents(agent.getAgent().toString());
				agent.closeAgent();
		}

		agent.consomme();
		agent.produit();


		// TRADE
		// TODO tester avant si on a de l'argent et de la place, ou refuser toutes les demandes?
		if(Constant.DEBUG_TRADE) System.out.println(agent.getLocalName()+" begin trade, search for "+agent.getRessourceConsommee().toString());

		// parcours l'annuaire
		sd.setType(agent.getRessourceConsommee().toString());
		template.addServices(sd);
		try {
			result = DFService.search(myAgent, template);
			agents = new AID[result.length];
			for(i=0; i<result.length; i++)
				agents[i] = result[i].getName();
		} catch (FIPAException fe) {
			fe.printStackTrace();
		}

		if(Constant.DEBUG_TRADE && (agents.length>0)) {
			System.out.println(agent.getLocalName()+" Services trouvés: "+agents.length);
			for(AID agent2 : agents)
				System.out.println(agent.getLocalName()+" "+agent2.getLocalName());
		}

		// envoi les demandes
		if(agents.length>0)
			if(agent.getReponsePropMissing() <= 0) {
				cmd = AgentsCommunicationMsg.CFP.makeCommand(agent.getRessourceConsommee().toString());
				agent.sendMsg(agents, ACLMessage.CFP, cmd);
				// TODO si toutes les réponses n'ont pas été reçues?
				agent.setReponsePropMissing(agents.length);
				agent.setPrixProp(agents.length);
				agent.setQuantite(agents.length);
				agent.setMarchandsContactes(new AID[agents.length]);
				agent.setPrixLePlusBas(Double.MAX_VALUE);
				agent.setMarchandChoisi(0);
				agent.setQuantiteRequise(0);
			} else {
				if(Constant.DEBUG) System.out.println(agent.getLocalName()+" il manque des réponses aux demandes ("+agent.getReponsePropMissing()+")");
				agent.setReponsePropMissing(0);
			}
	}

}
